package br.com.java.beans;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import org.apache.log4j.Logger;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.UploadedFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import br.com.java.entities.Aluno;
import br.com.java.entities.Arquivo;
import br.com.java.entities.EstadoCivil;
import br.com.java.entities.GrauInstrucao;
import br.com.java.entities.Modulo;
import br.com.java.entities.TipoArquivo;
import br.com.java.service.AlunoService;
import br.com.java.service.ArquivoService;
import br.com.java.service.ModuloService;
import br.com.java.util.BackupDataBase;

@Component
@Scope("session")
public class CadastroBean implements Serializable{
	
	private static final long serialVersionUID = 1880935315548336037L;

	private static Logger LOGGER = Logger.getLogger("CadastroBean");
	
	private String arquivoSql;
	private StreamedContent backupDatabase;
	
	private String nome;
	private String matricula;
	private Aluno aluno;
	private List<Aluno> listaAlunos = new ArrayList<Aluno>();
	private boolean adicionarCabecalho;
	
	@SuppressWarnings("unused")
	private Date dataAtual;
	
	private Arquivo arquivoAvatar;
	private UploadedFile uploadFileAvatar;
	private StreamedContent streamContentAvatar;
	private boolean contemAvatar = false;
	
	private Modulo modulo;
	private List<Modulo> listaModulos = new ArrayList<Modulo>();
	
	private String nomeArquivoObservacao;
	private UploadedFile uploadFileObservacao;
	private Arquivo arquivoObs;
	private List<Arquivo> listaArquivosObservacao = new ArrayList<Arquivo>();
	
	private String nomeArquivoInformacao;
	private UploadedFile uploadFileInformacao;
	private Arquivo arquivoInfo;
	private List<Arquivo> listaArquivosInformacao = new ArrayList<Arquivo>();
	
	private boolean editMode = false;
	private List<Modulo> copiaListaModulos = new ArrayList<Modulo>();
	private List<Arquivo> copiaListaArquivosObservacao = new ArrayList<Arquivo>();
	private List<Arquivo> copiaListaArquivosInformacao = new ArrayList<Arquivo>();
	
	@Autowired
	protected ApplicationContext context;
	
    @Autowired
    private AlunoService alunoService;
    @Autowired
    private ArquivoService arquivoService;
    @Autowired
    private ModuloService moduloService;
    
    @PostConstruct
    private void init() {
    	nome = "";
    	matricula = "";
    	getListaAlunos().clear();
    }
    
    //OPERAÇÕES BÁSICAS
    public String cadastrarAluno() {
        try {
        	
        	alunoService.saveOrUpdate(aluno);

        	for (Modulo mod : listaModulos) {
        		mod.setAluno(aluno);
        		moduloService.saveOrUpdate(mod);
        	}
        	
        	if(arquivoAvatar.getImagem() != null){
        		arquivoAvatar.setAluno(aluno);
        		arquivoService.saveOrUpdate(arquivoAvatar);
        	}
        	
        	for (Arquivo obs : listaArquivosObservacao) {
        		obs.setAluno(aluno);
        		arquivoService.saveOrUpdate(obs);
			}

        	for (Arquivo inf : listaArquivosInformacao) {
        		inf.setAluno(aluno);
        		arquivoService.saveOrUpdate(inf);
			}
        	
        	nome = "";
        	matricula = "";
        	
        	listaAlunos.clear();
        	listaAlunos.add(aluno);
        	
        	if(editMode){
        		for (Modulo m : copiaListaModulos) {
        			if (!listaModulos.contains(m)){
        				moduloService.remove(m);
        			}
				}
        		
        		for (Arquivo o : copiaListaArquivosObservacao) {
        			if (!listaArquivosObservacao.contains(o)){
        				arquivoService.remove(o);
        			}
    			}

            	for (Arquivo i : copiaListaArquivosInformacao) {
            		if (!listaArquivosInformacao.contains(i)){
        				arquivoService.remove(i);
        			}
    			}
        	}

        	message(FacesMessage.SEVERITY_INFO, "Aluno cadastrado com sucesso");
            
        } catch (IllegalStateException e1){
        	message(FacesMessage.SEVERITY_ERROR, e1.getMessage());
        	return "falha";
        	
        } catch (IllegalArgumentException e) {
            message(FacesMessage.SEVERITY_ERROR, e.getMessage());
            return "falha";
        }
        
        return "sucesso";
    }
    
    public String editarAluno(Aluno aluno) {
    	resetNovoAluno();
    	setAluno(aluno);
    	setEditMode(true);
    	copiaListaModulos.clear();
    	copiaListaArquivosInformacao.clear();
    	copiaListaArquivosObservacao.clear();

    	listaModulos.addAll(moduloService.pesquisarPorAluno(aluno));
    	copiaListaModulos.addAll(listaModulos);
    	Collections.copy(copiaListaModulos, listaModulos);
		
		List<Arquivo> arquivos = arquivoService.pesquisarPorAluno(aluno);
		
		for (Arquivo arquivo : arquivos){
			if (arquivo.getTipo().contentEquals(TipoArquivo.OBSERVACAO.toString())){
				listaArquivosObservacao.add(arquivo);
			} else if (arquivo.getTipo().contentEquals(TipoArquivo.INFORMACAO.toString())){
				listaArquivosInformacao.add(arquivo);
			} else if (arquivo.getTipo().contentEquals(TipoArquivo.FOTO.toString())){
				setArquivoAvatar(arquivo);
			}
		}

		copiaListaArquivosObservacao.addAll(listaArquivosObservacao);
		Collections.copy(copiaListaArquivosObservacao, listaArquivosObservacao);
		
		copiaListaArquivosInformacao.addAll(listaArquivosInformacao);
		Collections.copy(copiaListaArquivosInformacao, listaArquivosInformacao);
		
//		if (!getListaArquivosObservacao().isEmpty())
//			setCopiaListaArquivosObservacao(getListaArquivosObservacao());
//		if (!getListaArquivosInformacao().isEmpty())
//			setCopiaListaArquivosInformacao(getListaArquivosInformacao());
    	
		return "cadastrarAlunoInicio?faces-redirect=true"; //
    }
    
    public void excluirAluno(Aluno aluno) {
    	try {
    		alunoService.remove(aluno);
    		listaAlunos.remove(aluno);
    		message(FacesMessage.SEVERITY_INFO, "Aluno apagado com sucesso.");
		} catch (Exception e) {
			message(FacesMessage.SEVERITY_ERROR, "Erro ao apagar aluno: ");
			LOGGER.error(e.getMessage());
		}
    }
    
    public String cancelar(){
    	resetNovoAluno();
    	getListaAlunos().clear();
    	return "manterCadastro";
    }
    
	public void pesquisarAluno(){
    	listaAlunos = alunoService.pesquisarPorFiltro(matricula, nome);
    }
	
	public void selecionarAlunoImpressao(Aluno aluno){
//		aluno = new Aluno();
        getListaModulos().clear();
        
		setAluno(aluno);
		getListaModulos().addAll(moduloService.pesquisarPorAluno(aluno));
		
		//Se quiser que apareça essas listas na pre visualizacao de impressao (nao implementado na tela)
		
//		List<Arquivo> arquivos = arquivoService.pesquisarPorAluno(aluno);
//		
//		for (Arquivo arquivo : arquivos){
//			if (arquivo.getTipo().contentEquals(TipoArquivo.OBSERVACAO.toString())){
//				getListaArquivosObservacao().add(arquivo);
//			} else if (arquivo.getTipo().contentEquals(TipoArquivo.INFORMACAO.toString())){
//				getListaArquivosInformacao().add(arquivo);
//			}
//		}
		
	}
	
	private void resetNovoAluno(){
		aluno = new Aluno();
        getListaModulos().clear();
        arquivoAvatar = new Arquivo();
        streamContentAvatar = null;
        getListaArquivosObservacao().clear();
        getListaArquivosInformacao().clear();
        setEditMode(false);
	}
    
    //BACKUP DATABASE
	public StreamedContent getArquivoDownload(){

		InputStream stream = null; 
		String nomeSql = null;
		
		try {
			arquivoSql = BackupDataBase.gerarDumpDatabase();
//			Thread.sleep(5000);
			stream = new FileInputStream(arquivoSql);
			String[] caminhoSplit = arquivoSql.trim().split("\\\\");
			nomeSql = caminhoSplit[caminhoSplit.length-1];
			return new DefaultStreamedContent(stream, "application/octet-stream", nomeSql);
		
		} catch (FileNotFoundException e) {
			message(FacesMessage.SEVERITY_ERROR, "Arquivo SQL não encontrado para download.");
			LOGGER.error("Arquivo SQL não encontrado para download: " + e.getMessage());
			e.printStackTrace();
		} catch (IOException e1) {
			message(FacesMessage.SEVERITY_ERROR, "Problema na geração do arquivo SQL.");
			LOGGER.error("Problema na geração do arquivo SQL: " + e1.getMessage());
			e1.printStackTrace();
		} catch (Exception e3){
			message(FacesMessage.SEVERITY_ERROR, "Erro: " + e3.getMessage());
			LOGGER.error("Erro: " + e3.getMessage());
			e3.printStackTrace();
		}
		return null;
	} 
	
//	public void apagarArquivo(){
//		try {
//			BackupDataBase.apagarArquivo(arquivoSql);
//		} catch (IOException e) {
//			LOGGER.error("Erro: " + e.getMessage());
//			e.printStackTrace();
//		}
//	}
    
    //NAVEGACAO
    public String avancarCadastroInicio(){
    	
    	resetNovoAluno();
    	return "cadastrarAlunoInicio";
    }

    public String avancarCadastroMeio(){
    	
    	if (aluno.getNome().contentEquals("")){
    		message(FacesMessage.SEVERITY_WARN, "Nome do aluno é um campo obrigatório.");
    		return "";
    	}
    	
    	modulo = new Modulo();
    	
    	return "cadastrarAlunoMeio";
    }
    
    public String avancarCadastroFinal(){
    	
    	nomeArquivoObservacao = "";
    	arquivoObs = new Arquivo();
    	
    	nomeArquivoInformacao = "";
    	arquivoInfo = new Arquivo();
    	
    	return "cadastrarAlunoFim";
    }
    
    //METODOS PARA MODULO
    public String adicionarModulo(){
    	String nomeModulo = "";
    	
    	if (!modulo.getModulo().contentEquals("")){
    		if (!listaModulos.contains(modulo)){
    			listaModulos.add(modulo);
    			nomeModulo = modulo.getModulo();
    			message(FacesMessage.SEVERITY_INFO, "Modulo "+nomeModulo+" adicionado");
    		}
    		modulo = new Modulo();
    	} else {
    		message(FacesMessage.SEVERITY_WARN, "Nome do modulo é um campo obrigatório.");
    	}
    	
		return "";
	}
	
	public String removerModulo(Modulo modulo){
		String nomeModulo = modulo.getModulo();
		listaModulos.remove(modulo);
		message(FacesMessage.SEVERITY_INFO, "Modulo "+nomeModulo+" apagado!");
		return "";
	}
	
	public String editarModulo(Modulo modulo){
		setModulo(modulo);
		return "";
	}
    
    //METODOS PARA AVATAR
  	public void handleFileUploadAvatar(){
  		
  		if (uploadFileAvatar != null){
  			String extensao = uploadFileAvatar.getFileName().toString();
  			int tamanho = extensao.length();
  			
  			if(!extensao.equals("")){
  				extensao = extensao.substring(tamanho-4, tamanho);
  			}
  			
  			if(extensao.equals(".jpg")||extensao.equals(".png")||extensao.equals(".gif")){
  				
  				try {
  					salvarAvatar();
  					
  					message(FacesMessage.SEVERITY_INFO, "Imagem salva com sucesso!");
  				} catch (IOException e) {
  					message(FacesMessage.SEVERITY_ERROR, "Não foi possível salvar a imagem");
  					message(FacesMessage.SEVERITY_ERROR, e.getMessage());
  				}
  			}else{
  				message(FacesMessage.SEVERITY_WARN, "Formato de arquivo não suportado");
  			}
  		} else {
  			message(FacesMessage.SEVERITY_WARN, "É necessário selecionar um arquivo antes.");
  		}
  		
  	}
  	
  	public String salvarAvatar() throws IOException{
  		
  		streamContentAvatar = new DefaultStreamedContent(uploadFileAvatar.getInputstream());
  		arquivoAvatar.setNome(uploadFileAvatar.getFileName().toString());
  		arquivoAvatar.setTipo(TipoArquivo.FOTO.toString());
  		arquivoAvatar.setImagem(uploadFileAvatar.getContents());
  		
  		setContemAvatar(true);
  		
  		return "";
  	}
  	
  	//METODOS PARA OBSERVAÇÃO
  	public void handleFileUploadObservacao() throws UnsupportedEncodingException{
  		
  		if (uploadFileObservacao != null){
	  		String extensao = uploadFileObservacao.getFileName().toString();
	  		int tamanho = extensao.length();
	  		
	  		if(!extensao.equals("")){
	  			extensao = extensao.substring(tamanho-4, tamanho);
	  		}
	  		
	  		if(extensao.equals(".jpg")||extensao.equals(".png")||extensao.equals(".gif")||extensao.equals(".pdf")){
	  			
	  			if(nomeArquivoObservacao == null || nomeArquivoObservacao.equals("")){
					nomeArquivoObservacao = "Sem nome";
				}
				
				arquivoObs.setNome(nomeArquivoObservacao);
				arquivoObs.setTipo(TipoArquivo.OBSERVACAO.toString());
				arquivoObs.setImagem(uploadFileObservacao.getContents());
				
				listaArquivosObservacao.add(arquivoObs);
				
				arquivoObs = new Arquivo();
				nomeArquivoObservacao = "";

				message(FacesMessage.SEVERITY_INFO, "Arquivo de Observação salvo com sucesso!");
	  		}else{
	  			message(FacesMessage.SEVERITY_WARN, "Formato de arquivo não suportado.");
	  		}
  		} else {
  			message(FacesMessage.SEVERITY_WARN, "É necessário selecionar um arquivo antes.");
  		}
  	}
  	
  	public String removerArquivoObservacao(Arquivo arquivo){
		listaArquivosObservacao.remove(arquivo);
  		return "";
  	}
  	
  	//METODOS PARA INFORMAÇÃO
  	public void handleFileUploadInformacao(){
  		
  		if (uploadFileInformacao != null){
  			String extensao = uploadFileInformacao.getFileName().toString();
  			int tamanho = extensao.length();
  			
  			if(!extensao.equals("")){
  				extensao = extensao.substring(tamanho-4, tamanho);
  			}
  			
  			if(extensao.equals(".jpg")||extensao.equals(".png")||extensao.equals(".gif")||extensao.equals(".pdf")){
  				
				if(nomeArquivoInformacao == null || nomeArquivoInformacao.equals("")){
					nomeArquivoInformacao = "Sem nome";
				}
				
				arquivoInfo.setNome(nomeArquivoInformacao);
				arquivoInfo.setTipo(TipoArquivo.INFORMACAO.toString());
				arquivoInfo.setImagem(uploadFileInformacao.getContents());
				
				listaArquivosInformacao.add(arquivoInfo);
				
				arquivoInfo = new Arquivo();
				nomeArquivoInformacao = "";
				
				message(FacesMessage.SEVERITY_INFO, "Arquivo de Informação salvo com sucesso!");
  					
  			}else{
  				message(FacesMessage.SEVERITY_WARN, "Formato de arquivo não suportado.");
  			}
  		} else {
  			message(FacesMessage.SEVERITY_WARN, "É necessário selecionar um arquivo antes.");
  		}
  	}
  	
  	public String removerArquivoInformacao(Arquivo arquivo){
		listaArquivosInformacao.remove(arquivo);
  		return "";
  	}
  	
  	//CARREGAMENTO DOS COMBOS
    public List<SelectItem> getListaGrauInstrucao(){
    	
		List<SelectItem> selectables = new ArrayList<SelectItem>(); 
		
		for (GrauInstrucao grau : GrauInstrucao.values()){
			selectables.add(new SelectItem(grau.getGrauInstrucao()));
		}
		return selectables;
	}
	
	public List<SelectItem> getListaEstadoCivil(){
		
		List<SelectItem> selectables = new ArrayList<SelectItem>(); 
		for (EstadoCivil civil: EstadoCivil.values()){
			selectables.add(new SelectItem(civil));
		}
		return selectables;
	}
	
	private void message(Severity severity, String msg) {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, msg, ""));
    }
	
	public String getMatricula() {
		return matricula;
	}

	public void setMatricula(String matricula) {
		this.matricula = matricula;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public Aluno getAluno() {
		return aluno;
	}

	public void setAluno(Aluno aluno) {
		this.aluno = aluno;
	}

	public StreamedContent getStreamContentAvatar() {
		
		if (getArquivoAvatar() != null && getArquivoAvatar().getImagem() != null){
			streamContentAvatar = new DefaultStreamedContent(new ByteArrayInputStream(getArquivoAvatar().getImagem()));
		}
		return streamContentAvatar;
	}

	public void setStreamContentAvatar(StreamedContent streamContentAvatar) {
		this.streamContentAvatar = streamContentAvatar;
	}

	public Arquivo getArquivoAvatar() {
		return arquivoAvatar;
	}

	public void setArquivoAvatar(Arquivo arquivoAvatar) {
		this.arquivoAvatar = arquivoAvatar;
	}

	public UploadedFile getUploadFileAvatar() {
		return uploadFileAvatar;
	}

	public void setUploadFileAvatar(UploadedFile uploadFileAvatar) {
		this.uploadFileAvatar = uploadFileAvatar;
	}

	public boolean isContemAvatar() {
		return contemAvatar;
	}

	public void setContemAvatar(boolean contemAvatar) {
		this.contemAvatar = contemAvatar;
	}

	public Modulo getModulo() {
		return modulo;
	}

	public void setModulo(Modulo modulo) {
		this.modulo = modulo;
	}

	public List<Modulo> getListaModulos() {
		return listaModulos;
	}

	public void setListaModulos(List<Modulo> listaModulos) {
		this.listaModulos = listaModulos;
	}

	public String getNomeArquivoObservacao() {
		return nomeArquivoObservacao;
	}

	public void setNomeArquivoObservacao(String nomeArquivoObservacao) {
		this.nomeArquivoObservacao = nomeArquivoObservacao;
	}

	public UploadedFile getUploadFileObservacao() {
		return uploadFileObservacao;
	}

	public void setUploadFileObservacao(UploadedFile uploadFileObservacao) {
		this.uploadFileObservacao = uploadFileObservacao;
	}

	public Arquivo getArquivoObs() {
		return arquivoObs;
	}

	public void setArquivoObs(Arquivo arquivoObs) {
		this.arquivoObs = arquivoObs;
	}

	public List<Arquivo> getListaArquivosObservacao() {
		return listaArquivosObservacao;
	}

	public void setListaArquivosObservacao(List<Arquivo> listaArquivosObservacao) {
		this.listaArquivosObservacao = listaArquivosObservacao;
	}

	public String getNomeArquivoInformacao() {
		return nomeArquivoInformacao;
	}

	public void setNomeArquivoInformacao(String nomeArquivoInformacao) {
		this.nomeArquivoInformacao = nomeArquivoInformacao;
	}

	public UploadedFile getUploadFileInformacao() {
		return uploadFileInformacao;
	}

	public void setUploadFileInformacao(UploadedFile uploadFileInformacao) {
		this.uploadFileInformacao = uploadFileInformacao;
	}

	public Arquivo getArquivoInfo() {
		return arquivoInfo;
	}

	public void setArquivoInfo(Arquivo arquivoInfo) {
		this.arquivoInfo = arquivoInfo;
	}

	public List<Arquivo> getListaArquivosInformacao() {
		return listaArquivosInformacao;
	}

	public void setListaArquivosInformacao(List<Arquivo> listaArquivosInformacao) {
		this.listaArquivosInformacao = listaArquivosInformacao;
	}

	public List<Aluno> getListaAlunos() {
		return listaAlunos;
	}

	public void setListaAlunos(List<Aluno> listaAlunos) {
		this.listaAlunos = listaAlunos;
	}

	public StreamedContent getBackupDatabase() {
		return backupDatabase;
	}

	public void setBackupDatabase(StreamedContent backupDatabase) {
		this.backupDatabase = backupDatabase;
	}

	public boolean isAdicionarCabecalho() {
		return adicionarCabecalho;
	}

	public void setAdicionarCabecalho(boolean adicionarCabecalho) {
		this.adicionarCabecalho = adicionarCabecalho;
	}

	public String getArquivoSql() {
		return arquivoSql;
	}

	public void setArquivoSql(String arquivoSql) {
		this.arquivoSql = arquivoSql;
	}

	public String getDataAtual() {
		SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
		return sdf.format(new Date());
	}

	public void setDataAtual(Date dataAtual) {
		this.dataAtual = dataAtual;
	}

	public boolean isEditMode() {
		return editMode;
	}

	public void setEditMode(boolean editMode) {
		this.editMode = editMode;
	}

	public List<Modulo> getCopiaListaModulos() {
		return copiaListaModulos;
	}

	public void setCopiaListaModulos(List<Modulo> copiaListaModulos) {
		this.copiaListaModulos = copiaListaModulos;
	}

	public List<Arquivo> getCopiaListaArquivosObservacao() {
		return copiaListaArquivosObservacao;
	}

	public void setCopiaListaArquivosObservacao(
			List<Arquivo> copiaListaArquivosObservacao) {
		this.copiaListaArquivosObservacao = copiaListaArquivosObservacao;
	}

	public List<Arquivo> getCopiaListaArquivosInformacao() {
		return copiaListaArquivosInformacao;
	}

	public void setCopiaListaArquivosInformacao(
			List<Arquivo> copiaListaArquivosInformacao) {
		this.copiaListaArquivosInformacao = copiaListaArquivosInformacao;
	}
}